﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace JackProjectTemplate.Shared.Extensions
{
    public static class ConfigureServiceCollectionExtensions
    {
        public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
        {
            ArgumentNullException.ThrowIfNull(services);
            ArgumentNullException.ThrowIfNull(configuration);

            var config = new TConfig();
            configuration.Bind(config);
            services.AddSingleton(config);
            return config;
        }

        public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration, Func<TConfig> pocoProvider) where TConfig : class
        {
            ArgumentNullException.ThrowIfNull(services);
            ArgumentNullException.ThrowIfNull(configuration);
            ArgumentNullException.ThrowIfNull(pocoProvider);

            var config = pocoProvider();
            configuration.Bind(config);
            services.AddSingleton(config);
            return config;
        }

        public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration, TConfig config) where TConfig : class
        {
            ArgumentNullException.ThrowIfNull(services);
            ArgumentNullException.ThrowIfNull(configuration);
            ArgumentNullException.ThrowIfNull(config);

            configuration.Bind(config);
            services.AddSingleton(config);
            return config;
        }

        public static TConfig ConfigureOptions<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
        {
            ArgumentNullException.ThrowIfNull(services);
            ArgumentNullException.ThrowIfNull(configuration);

            var config = new TConfig();
            configuration.Bind(config);
            services.AddSingleton(config);
            services.Configure<TConfig>(configuration);
            return config;
        }

        public static ConfigurationManager GetConfigurationManager(this IServiceCollection services)
        {
            ConfigurationManager? configurationManager = services.FirstOrDefault(x => x.ServiceType == typeof(IConfiguration))?.ImplementationInstance as ConfigurationManager;
            ArgumentNullException.ThrowIfNull(configurationManager);
            return configurationManager;
        }

        public static TService GetRequiredService<TService>(this IServiceCollection services)
            where TService : class
        {
            TService? service = services.FirstOrDefault(x => x.ServiceType == typeof(TService))?.ImplementationInstance as TService;
            ArgumentNullException.ThrowIfNull(service);
            return service;
        }

        public static TService? GetService<TService>(this IServiceCollection services)
            where TService : class
        {
            TService? service = services.FirstOrDefault(x => x.ServiceType == typeof(TService))?.ImplementationInstance as TService;
            return service;
        }
    }
}
